# -*- coding: utf-8 -*-

'''
@project : SmartHomeVideo
@FileName: mq_rpc
@Author  :linych
@Time    :2021/2/22 15:33
@Desc  :
'''

import asyncio
import random
import uuid
from aio_pika import connect, IncomingMessage, Message
import time



class RabbitMQRpcClient:

    loop = asyncio.get_event_loop()
    connection = None
    host = None
    port = None
    login = None
    password = None
    queue = None



    channl_list = None

    futures ={}

    loop_lock = asyncio.Lock(loop=loop)
    connect_lock = asyncio.Lock(loop=loop)


    # async def init_loop(self):
    #
    #     if RabbitMQRpcClient.loop is None:
    #         async with RabbitMQRpcClient.loop_lock:
    #             if RabbitMQRpcClient.loop is None:
    #                 RabbitMQRpcClient.loop = asyncio.get_event_loop()

    async def init_connect(self):

        if RabbitMQRpcClient.loop is None or RabbitMQRpcClient.channl_list is None:
            async with RabbitMQRpcClient.connect_lock:
                if RabbitMQRpcClient.loop is None or RabbitMQRpcClient.channl_list is None:

                    print('connect....................')
                    RabbitMQRpcClient.connection = await connect(
                        host=self.host, port=self.port, loop=RabbitMQRpcClient.loop, login=self.login, password=self.password
                    )
                    print('connect finish')
                    channel_list= []
                    for i in range(2):
                        channel = await self.connection.channel()
                        callback_queue = await channel.declare_queue(exclusive=True)
                        await callback_queue.consume(self.on_response)

                        channel_list.append((channel, callback_queue))
                    RabbitMQRpcClient.channl_list = channel_list
                    print('channel finish ')


    async def re_connect(self):

        async with RabbitMQRpcClient.connect_lock:

            print('connect....................')
            RabbitMQRpcClient.connection = await connect(
                host=self.host, port=self.port, loop=RabbitMQRpcClient.loop, login=self.login, password=self.password
            )
            print('connect finish')
            for i in range(2):
                channel = await self.connection.channel()
                callback_queue = await channel.declare_queue(exclusive=True)
                await callback_queue.consume(self.on_response)

                RabbitMQRpcClient.channl_list.append((channel, callback_queue))
            print('channel finish ')



    def on_response(self, message: IncomingMessage):
        print('response ....{}'.format(time.time()))
        future = RabbitMQRpcClient.futures.pop(message.correlation_id)
        future.set_result(message.body)

    async def call(self, correlation_id='',body=''):

        # await self.init_loop()
        await self.init_connect()


        channel,callback_queue = random.choice(RabbitMQRpcClient.channl_list)


        if correlation_id is '':
            correlation_id = str(uuid.uuid4())

        future = RabbitMQRpcClient.loop.create_future()

        RabbitMQRpcClient.futures[correlation_id] = future


        s = time.time()
        try:
            await channel.default_exchange.publish(
                Message(
                    str(body).encode(),
                    content_type="text/plain",
                    correlation_id=correlation_id,
                    reply_to=callback_queue.name,
                ),
                routing_key=self.queue,
            )
        except Exception as e:

            print('publish error : {}...'.format(e))
            await self.re_connect()
            await channel.default_exchange.publish(
                Message(
                    str(body).encode(),
                    content_type="text/plain",
                    correlation_id=correlation_id,
                    reply_to=callback_queue.name,
                ),
                routing_key=self.queue,
            )

        res = await future

        print('doing.. {}'.format(time.time()-s))

        return res
